package cn.imnaer.service.rpc.userinfo.impl;

import cn.imnaer.service.persistence.model.FriendRelation;
import cn.imnaer.service.persistence.model.FriendRequest;
import cn.imnaer.service.persistence.model.TemporarySession;
import cn.imnaer.service.persistence.model.User;
import cn.imnaer.service.persistence.model.consts.FRIEND_REQUEST;
import cn.imnaer.service.rest.resquest.model.FriendRelationParams;
import cn.imnaer.service.rest.view.model.FriendRequestResponse;
import cn.imnaer.service.rest.view.model.SimpleUser;
import cn.imnaer.service.rpc.enums.EnumFriendRequestStatus;
import cn.imnaer.service.rpc.userinfo.FriendRelationComponentRpcApi;
import cn.imnaer.service.rpc.userinfo.dao.FriendRelationDaoImpl;
import cn.imnaer.service.rpc.userinfo.dao.FriendRequestDaoImpl;
import cn.imnaer.service.rpc.userinfo.dao.UserDaoImpl;

import java.util.*;

import org.bson.BSONObject;
import org.bson.BasicBSONObject;

/**
 * Created by Administrator on 2015/5/22.
 */
public class FriendRelationComponentRpcApiImpl implements
		FriendRelationComponentRpcApi {

	/**
	 * 新好友通知数量
	 */
	private final static Map<String, Long> cache_newFriendNoticeCount = new HashMap<>();

	private FriendRelationDaoImpl friendRelationActiveRecord = FriendRelationDaoImpl
			.getInstance();
	private FriendRequestDaoImpl friendRequestActiveRecord = FriendRequestDaoImpl
			.getInstance();
	private UserDaoImpl userActiveRecord = UserDaoImpl.getInstance();

	@Override
	public List<FriendRelation> findByUserId(String userId) {
		return friendRelationActiveRecord.findByUserId(userId);
	}

	@Override
	public List<FriendRelation> findByUserId(User user) {
		return this.findByUserId(user.getUserId());
	}

	@Override
	public List<FriendRelation> findRealFriendRelationsByUserId(User user) {
		return this.findRealFriendRelationsByUserId(user.getUserId());
	}

	@Override
	public List<FriendRelation> findRealFriendRelationsByUserId(String userId) {

		return this.friendRelationActiveRecord.findRealByUserId(userId);
	}

	@Override
	public List<String> findRealFriendUserIdsByUserId(String userId) {
		List<String> result = new ArrayList<>();
		List<FriendRelation> friendRelations = this
				.findRealFriendRelationsByUserId(userId);
		for (FriendRelation friendRelation : friendRelations) {
			result.add(friendRelation.getFriendUserId());
		}
		return result;
	}

	@Override
	public SimpleUser buildFriendRelations(String userId, String targetUserId) {
		FriendRelation selfUserRelation = this.friendRelationActiveRecord
				.findBySelfUserIdAndTargetUserId(userId, targetUserId);
		FriendRelation targetUserRelation = this.friendRelationActiveRecord
				.findBySelfUserIdAndTargetUserId(targetUserId, userId);
		if (selfUserRelation == null && targetUserRelation == null) { // 从未建立过好友关系

			selfUserRelation = new FriendRelation(userId, targetUserId);
			selfUserRelation.setEachOther(true);
			targetUserRelation = new FriendRelation(targetUserId, userId);
			targetUserRelation.setEachOther(true);
			this.friendRelationActiveRecord
					.insert(selfUserRelation,true);
			this.friendRelationActiveRecord
					.insert(targetUserRelation,true);

		} else if (!selfUserRelation.getEachOther()
				&& !targetUserRelation.getEachOther()) { // 建立过好友关系, 但有一方删除了对方

			this.settingAndUpdateRelationByEachOtherStatus(selfUserRelation,
					targetUserRelation, true);
		}

		// 推送出来了要删除掉
		// 这里只能接收方同意发送方的请求, 所以targetUserId为发送方, 接收方为 userId (selfUserId)
		FriendRequest friendRequest = this.friendRequestActiveRecord
				.findBySendUserAndAcceptUser(targetUserId, userId);
		friendRequest.setStatus(EnumFriendRequestStatus.ADDED.getValue());
		BSONObject matcher = new BasicBSONObject();
		matcher.put(FRIEND_REQUEST.friendRequestId,
				friendRequest.getFriendRequestId());
		this.friendRequestActiveRecord.update(matcher, friendRequest);
		// 缓存, 推送出来要删掉
		cache_newFriendNoticeCount.put(targetUserId, 1L);
		User targetUser = this.userActiveRecord.findOneByPk(targetUserId);
		SimpleUser su = new SimpleUser(targetUser);

		return su;
	}

	public Long countNewFriendNotice(String userId) {
		if (!cache_newFriendNoticeCount.containsKey(userId)) {
			return 0L;
		}
		Long newFriendNotice = cache_newFriendNoticeCount.get(userId);
		cache_newFriendNoticeCount.put(userId, 0L);
		return newFriendNotice;
	}

	@Override
	public boolean deleteFriendRelation(String selfUserId, String targetUserId) {
		FriendRelation selfUserRelation = this.friendRelationActiveRecord
				.findBySelfUserIdAndTargetUserId(selfUserId, targetUserId);
		FriendRelation targetUserRelation = this.friendRelationActiveRecord
				.findBySelfUserIdAndTargetUserId(targetUserId, selfUserId);
		if (selfUserRelation == null && targetUserRelation == null) { // 从未建立过好友关系
			return false;
		} else {
			this.settingAndUpdateRelationByEachOtherStatus(selfUserRelation,
					targetUserRelation, false);
		}
		return true;
	}

	@Override
	public boolean updateFriendRelation(String selfUserId, String targetUserId,
			String note, boolean isStart) {
		FriendRelation selfUserRelation = this.friendRelationActiveRecord
				.findBySelfUserIdAndTargetUserId(selfUserId, targetUserId);
		if (selfUserRelation == null) { // 从未建立过好友关系
			return false;
		} else {
			selfUserRelation.setNote(note);
			selfUserRelation.setIsStar(isStart);

			this.friendRelationActiveRecord.update(selfUserRelation);
		}
		return true;
	}

	@Override
	public boolean updateFriendRelation(FriendRelationParams request) {
		return this.updateFriendRelation(request.getUserId(),
				request.getFriendUserId(), request.getNote(),
				request.getIsStar());
	}

	@Override
	public List<String> findRealFriendUserIdsByUserId(User user) {
		return this.findRealFriendUserIdsByUserId(user.getUserId());
	}

	public FriendRequest sendPaper(String sendUserId, String acceptUserId,
			String content) {

		FriendRequest request = new FriendRequest();
		User sendUser = this.userActiveRecord.findOneByPk(sendUserId);
		User acceptUser = this.userActiveRecord.findOneByPk(acceptUserId);
		request.setSendUserId(sendUserId);
		request.setSendUserName(sendUser.getName());
		request.setAcceptUserId(acceptUserId);
		request.setAcceptUserName(acceptUser.getName());
		request.setCreateTime(new Date().getTime());
		request.setStatus(EnumFriendRequestStatus.UN_ADD.getValue());

		TemporarySession session = new TemporarySession().buildSession(content,
				request, sendUserId);
		request.sendSession(session);

		this.friendRequestActiveRecord.insert(request,true);

		return request;

	}

	public FriendRequest replyPaper(String requestId, String sendUserId,
			String content) {
		FriendRequest request = this.friendRequestActiveRecord
				.findOneByPk(requestId);
		TemporarySession session = new TemporarySession().buildSession(content,
				request, sendUserId);
		request.sendSession(session);
		this.friendRequestActiveRecord.update(request);
		return request;
	}

	@Override
	public Long countUnReadFriendRequest(String userId) {
		Long sumCount = 0L;
		sumCount += this.friendRequestActiveRecord
				.countUnReadBySendUser(userId);
		sumCount += this.friendRequestActiveRecord
				.countUnReadByAcceptUser(userId);
		return sumCount;
	}

	public List<FriendRequestResponse> findUnReadFriendRequest(String userId) {
		List<FriendRequest> allUnReadFriendRequest = new ArrayList<>();
		List<FriendRequest> unReadFriendRequestOfSend = this.friendRequestActiveRecord
				.findUnReadBySendUser(userId);
		List<FriendRequest> unReadFriendRequestOfAccept = this.friendRequestActiveRecord
				.findUnReadByAcceptUser(userId);
		allUnReadFriendRequest.addAll(unReadFriendRequestOfSend);
		allUnReadFriendRequest.addAll(unReadFriendRequestOfAccept);
		Collections.sort(allUnReadFriendRequest,
				new Comparator<FriendRequest>() {
					@Override
					public int compare(FriendRequest o1, FriendRequest o2) {
						return (int) (o2.getCreateTime() - o1.getCreateTime());
					}
				});

		this.friendRequestActiveRecord
				.batchTagReadBySendUser(unReadFriendRequestOfSend);
		this.friendRequestActiveRecord
				.batchTagReadByAcceptUser(unReadFriendRequestOfAccept);
		List<FriendRequestResponse> result = FriendRequestResponse
				.parseList(allUnReadFriendRequest);
		return result;
	}

	public List<FriendRequestResponse> findAllFriendRequest(String userId) {
		List<FriendRequest> allUnReadFriendRequest = new ArrayList<>();
		List<FriendRequest> friendRequestOfSend = this.friendRequestActiveRecord
				.findBySendUser(userId);
		List<FriendRequest> friendRequestOfAccept = this.friendRequestActiveRecord
				.findByAcceptUser(userId);
		this.batchTagRead(friendRequestOfSend, friendRequestOfAccept);

		allUnReadFriendRequest.addAll(friendRequestOfSend);
		allUnReadFriendRequest.addAll(friendRequestOfAccept);
		Collections.sort(allUnReadFriendRequest,
				new Comparator<FriendRequest>() {
					@Override
					public int compare(FriendRequest o1, FriendRequest o2) {
						return (int) (o2.getCreateTime() - o1.getCreateTime());
					}
				});

		List<FriendRequestResponse> result = FriendRequestResponse
				.parseList(allUnReadFriendRequest);
		return result;
	}

	/**
	 * 批量标记已读
	 *
	 * @param friendRequestOfSend
	 * @param friendRequestOfAccept
	 */
	private void batchTagRead(List<FriendRequest> friendRequestOfSend,
			List<FriendRequest> friendRequestOfAccept) {
		List<FriendRequest> unReadFriendRequestOfSend = new ArrayList<>();
		List<FriendRequest> unReadFriendRequestOfAccept = new ArrayList<>();
		// 筛选所有未读信息
		for (FriendRequest friendRequest : friendRequestOfAccept) {
			if (friendRequest.getIsUnReadForAcceptUser()) {
				unReadFriendRequestOfAccept.add(friendRequest);
			}
		}
		// 筛选所有未读信息
		for (FriendRequest friendRequest : friendRequestOfSend) {
			if (friendRequest.getIsUnReadForSendUser()) {
				unReadFriendRequestOfSend.add(friendRequest);
			}
		}

		this.friendRequestActiveRecord
				.batchTagReadBySendUser(unReadFriendRequestOfSend);
		this.friendRequestActiveRecord
				.batchTagReadByAcceptUser(unReadFriendRequestOfAccept);
	}

	public void deleteFriendRequest(String requestId) {
		this.friendRequestActiveRecord.deleteByPk(requestId);
	}

	/**
	 * 更新好友双方关系
	 * <p>
	 * 1. 统一 EachOther 字段. <br>
	 * 2. 如果主动删除好友关系 : <br>
	 * 则设置自身与对方好友关系removed 为 true <br>
	 * 对方的好友与自身关系removed 字段保持不变
	 * </p>
	 *
	 * @param selfUserRelation
	 * @param targetUserRelation
	 * @param isBuildEachOther
	 */
	private void settingAndUpdateRelationByEachOtherStatus(
			FriendRelation selfUserRelation, FriendRelation targetUserRelation,
			boolean isBuildEachOther) {
		if (!isBuildEachOther) {
			selfUserRelation.setRemoved(true);
		} else {
			selfUserRelation.setRemoved(false);
			targetUserRelation.setRemoved(false);
		}
		selfUserRelation.setEachOther(isBuildEachOther);
		targetUserRelation.setEachOther(isBuildEachOther);
		this.friendRelationActiveRecord.update(selfUserRelation);
		this.friendRelationActiveRecord.update(targetUserRelation);
	}

}
